package de.szut.dqi12.sqlitebrowser.view;

import java.awt.BorderLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.JTree;
import javax.swing.JTextField;

import java.awt.GridLayout;
import java.io.File;

import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeSelectionModel;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JSplitPane;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;

import de.szut.dqi12.sqlitebrowser.controller.ErrorMessages;
import de.szut.dqi12.sqlitebrowser.controller.GUIController;import de.szut.dqi12.sqlitebrowser.model.Table;


@SuppressWarnings("serial")
public class View extends JFrame {

	public static final String CONNECTION = "Database Connection";
	public static final String NO_CONNECTION = "No Database Connection";
	
	private DefaultMutableTreeNode defaultNode;
	private JTextField commandTextField;
	private JButton executeQueryButton;
	private JTextField downLimit;
	private JTextField upLimit;
	private JScrollPane tableScrollPane = new JScrollPane();
	private JCheckBox limitCheck;
	private JLabel connectionLabel;
	private JTree tree;
	private JTable table;
	private GUIController guiController;
	private JMenuItem menuItemLoad;

	/**
	 * Create the frame.
	 */
	public View() {
		guiController = GUIController.getInstance(this);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		addWindowListener(new MyWindowListener());
		setBounds(guiController.getController().getFrameBounds());
		buildGUI();
	}
	
	/**
	 * Builds the GUI Components
	 * good looks aren't everything
	 */
	
	private void buildGUI() {
		JPanel panel = new JPanel();
		setContentPane(panel);
		panel.setLayout(new BorderLayout(0, 0));
		buildMenuBar();
		JPanel connectionPanel = new JPanel();
		panel.add(connectionPanel, BorderLayout.SOUTH);
		connectionPanel.setLayout(new BorderLayout(0, 0));
		connectionLabel = new JLabel("No database Connection");
		connectionLabel.setHorizontalAlignment(SwingConstants.RIGHT);
		connectionPanel.add(connectionLabel, BorderLayout.NORTH);
		JSplitPane splitPane = new JSplitPane();
		panel.add(splitPane, BorderLayout.CENTER);
		JPanel tablePanel = new JPanel();
		splitPane.setRightComponent(tablePanel);
		tablePanel.setLayout(new BorderLayout(0, 0));
		JPanel limitPanel = new JPanel();
		tablePanel.add(limitPanel, BorderLayout.SOUTH);
		limitCheck = new JCheckBox("Limit");
		downLimit = new JTextField();
		downLimit.setEditable(false);
		upLimit = new JTextField();
		upLimit.setEditable(false);
		downLimit.setToolTipText("von");
		upLimit.setToolTipText("bis");
		limitPanel.setLayout(new BorderLayout());
		limitPanel.add(limitCheck, BorderLayout.WEST);
		JPanel limitFieldPanel = new JPanel(new GridLayout(0, 2, 0, 0));
		limitFieldPanel.add(downLimit);
		limitFieldPanel.add(upLimit);
		limitPanel.add(limitFieldPanel, BorderLayout.CENTER);
		JPanel commandPanel = new JPanel();
		tablePanel.add(commandPanel, BorderLayout.NORTH);
		commandPanel.setLayout(new BorderLayout());
		commandTextField = new JTextField();
		executeQueryButton = new JButton("Execute Query");
		executeQueryButton.setSize(executeQueryButton.getWidth(), 7);
		commandPanel.add(commandTextField, BorderLayout.CENTER);
		commandPanel.add(executeQueryButton, BorderLayout.EAST);
		tablePanel.add(tableScrollPane, BorderLayout.CENTER);
		table = new JTable();
		tableScrollPane.setViewportView(table);
		JScrollPane treeScrollPane = new JScrollPane();
		splitPane.setLeftComponent(treeScrollPane);
		defaultNode = new DefaultMutableTreeNode("Database");
		addExecuteQueryActionListener();
		addLimitCheckboxActionListener();
		buildTree();
		treeScrollPane.setViewportView(tree);
		revalidate();
		repaint();
	}
	
	/**
	 * creates the Menu Bar
	 * adds the Menu Bar to the frame
	 */
	
	private void buildMenuBar() {
		JMenuBar menuBar = new JMenuBar();
		setJMenuBar(menuBar);
		JMenu menuFile = new JMenu("File");
		menuBar.add(menuFile);
		menuItemLoad = new JMenuItem("Load database");
		menuItemLoad.addActionListener(e -> {
			JFileChooser fileChooser = new JFileChooser();
			FileFilter fileFilter = new FileNameExtensionFilter("Datenbank", "db3");
			fileChooser.setFileFilter(fileFilter);
			try {
				fileChooser.setCurrentDirectory(new File(guiController.getController().getLastDatabasePath()));
			} catch(Exception a) {
				GUIController.getInstance().executeErrorMessageDialog(ErrorMessages.FAIL);
			}
			fileChooser.showOpenDialog(this);
			if(fileChooser.getSelectedFile() != null) {
				guiController.getController().openDatabase(fileChooser.getSelectedFile());
			}
		});
		menuFile.add(menuItemLoad);
	}
	
	/**
	 * creates the JTree
	 * adds the JTree to the frame
	 */
	
	private void buildTree() {
		tree = new JTree(defaultNode);
		tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
		addTreeListener(tree);
	}
	
	/**
	 * add a tree listener to a tree
	 * @param tree - a tree
	 */
	
	private void addTreeListener(JTree tree) {
		tree.addTreeSelectionListener(e -> {
			DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
			if(node.getChildCount() == 0) {
				Table content = guiController.getController().openTable(node.getUserObject().toString(), limitCheck.isSelected(), downLimit.getText(), upLimit.getText());
				addDataToTable(content);
			} 
		});
	}
	
	/**
	 * add a ActionListener on the executeQueryButton (Submit Button)
	 */
	
	private void addExecuteQueryActionListener() {
		executeQueryButton.addActionListener(e -> {
			addDataToTable(guiController.getController().executeQuery(commandTextField.getText(), limitCheck.isSelected(), downLimit.getText(), upLimit.getText()));
		});
	}
	
	/**
	 * add a ActionListener on the limitCheckBox
	 */
	
	private void addLimitCheckboxActionListener() {
		limitCheck.addActionListener(e -> {
			if(limitCheck.isSelected()) {
				downLimit.setEditable(true);
				upLimit.setEditable(true);
			} else {
				downLimit.setEditable(false);
				upLimit.setEditable(false);
			}
		});
	}
	
	/**
	 * adds the table data to the JTable
	 * @param table - Table object with all informations to update the JTable on the view
	 */
	
	private void addDataToTable(Table table) {
		try {
			this.table.setModel(new DefaultTableModel(table.getContent(), table.getColumnNames()));
			repaint();	
		} catch(Exception e) {}
	}
	
	/**
	 * adds database data to the jtree
	 * @param dbName - name of the database
	 * @param tables - name of the tables
	 * @return 
	 */
	
	public boolean addDatabaseToTree(String dbName, String[] tables) {
		if(dbName != null && tables != null) {
			buildTree();
			DefaultMutableTreeNode database = new DefaultMutableTreeNode(dbName);
			defaultNode.add(database);
			for (String s : tables) {
				DefaultMutableTreeNode table = new DefaultMutableTreeNode(s);
				database.add(table);
			}
			return true;
		}
		return false;
	}
	
	/**
	 * Sets the Text of the connectionLabel
	 * @param isConnected - true if there is a database
	 */
	
	public void setDatabaseConnection(boolean isConnected) {
		if(isConnected) {
			connectionLabel.setText(CONNECTION);
		} else {
			connectionLabel.setText(NO_CONNECTION);
		}
	}
	
	/**
	 * displays a JOptionPane with an error message
	 * @param errorMessage - error message
	 */
	
	public void executeErrorMessageDialog(String errorMessage) {
		JOptionPane.showMessageDialog(null,
                errorMessage,
                "ERROR!",					      
                JOptionPane.ERROR_MESSAGE);
	}
}